/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package slicktest.entities.ImmobileEntity;

import java.util.Collections;
import java.util.List;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;

import slicktest.data.StatMod;
import slicktest.entities.Drawable.DrawableEntity;
import slicktest.factories.ImageFactory;
import slicktest.types.DamageType;
import slicktest.util.StatModUtil;

/**
 *
 * @author enrightt
 */
public class Terrain implements ImmobileEntity, DrawableEntity {

    //the tower that is decorating this terrain, for stat mod calculations.
    private Tower tower;
    private boolean passable;
    private boolean buildable;
    private String type;
    //these are the stat mods innate to this type of terrain. Even if terrain
    //doesn't modify a given stat, it'll be present as {X, noop}. When specifiying a
    //decrease, use a negative number.
    private StatMod ROFMod;
    private StatMod damageMod;
    private StatMod projectileSpeedMod;
    private StatMod splashMod;
    private StatMod buildTimeMod;

    private boolean[][] footprint;

    private Image image;
    private float tlx;
    private float tly;

    //this will be only used by the marshallers to create the model version
    //of a given terrain
    public Terrain(boolean passable,
            boolean buildable,
            String type,
            StatMod ROFMod,
            StatMod damageMod,
            StatMod projectileSpeedMod,
            StatMod splashMod,
            StatMod buildTimeMod,
            String imgPath) throws SlickException {
        this.tower = null;
        this.passable = passable;
        this.buildable = buildable;
        this.type = type;
        this.ROFMod = ROFMod;
        this.damageMod = damageMod;
        this.projectileSpeedMod = projectileSpeedMod;
        this.splashMod = splashMod;
        this.buildTimeMod = buildTimeMod;

        //terrain technically does have a footprint, it's just 1x1.
        this.footprint = new boolean[1][1];
        footprint[0][0] = true;
        
        this.image = ImageFactory.getInstance().getImage(imgPath);
        this.tlx = 0.0F;
        this.tly = 0.0F;
    }
    
    //copy constructor to make Terrain from an existing one.
    public Terrain(Terrain t) {
        this.tower = null;
        this.passable = t.passable;
        this.buildable = t.buildable;
        this.type = t.type;
        this.ROFMod = t.ROFMod;
        this.damageMod = t.damageMod;
        this.projectileSpeedMod = t.projectileSpeedMod;
        this.splashMod = t.splashMod;
        this.buildTimeMod = t.buildTimeMod;
        this.image = t.image;
        this.tlx = 0.0F;
        this.tly = 0.0F;
        
    }

    //sets the tower sitting on top of this terrain.
    public void setTower(Tower t) {
        this.tower = t;
    }

    public double getROF() {
        double result = -1;

        if (tower != null) {
            return StatModUtil.aggregateDoubleStat(tower.getROF(), ROFMod);
        }

        return result;
    }

    public double getDamage() {
        double result = -1;

        if (tower != null) {
            result = StatModUtil.aggregateDoubleStat(tower.getDamage(), damageMod);
        }

        return result;
    }

    public double getProjectileSpeed() {
        double result = -1;

        if (tower != null) {
            result = StatModUtil.aggregateDoubleStat(tower.getProjectileSpeed(), projectileSpeedMod);
        }

        return result;
    }

    public double getSplash() {
        double result = -1;

        if (tower != null) {
            result = StatModUtil.aggregateDoubleStat(tower.getSplash(), splashMod);
        }

        return result;
    }

    //the way this'll work is when you create (build) a tower object, it will
    //calculate its build time on creation, then set some kind of "time until active"
    //field for update(dt) to use.
    public double getBuildTime() {
        double result = -1;

        if (tower != null) {
            result = StatModUtil.aggregateDoubleStat(tower.getBuildTime(), buildTimeMod);
        }

        return result;
    }

    //terrain won't modify the cost of a tower built on top of it.
    public double getCost() {
        return -1;
    }

    public boolean[][] getFootprint() {
        return footprint;
    }

    //terrain never has any damage type. The game will be interacting with Towers
    //decorating Terrain, so there's no need to take the tower into consideration.
    public List<DamageType> getDamageTypes() {
        return Collections.EMPTY_LIST;
    }

    public String getType() {
        return type;
    }

    //when dealing with a tower, you'll be dealing with the tower
    //wrapping this Terrain, ergo there'll be no need to add in a condition to use
    //the tower's value if it's set. 
    public boolean isBuildable() {
        return buildable;
    }

    public boolean isPassable() {
        return passable;
    }

    //never any build restrictions on Terrain, since it won't be built directly.
    public List<String> getRestrictions() {
        return Collections.EMPTY_LIST;
    }

    public void update(GameContainer gc, int delta) throws SlickException {

    }

    public void setX(float x) {
        this.tlx = x;
    }

    public void setY(float y) {
        this.tly = y;
    }

    public void render(GameContainer gc, Graphics graphics) throws SlickException {
        graphics.drawImage(image, tlx, tly);
    }

    @Override
    public String toString() {
        return "Terrain{" + "tower=" + tower + "passable=" + passable + "buildable=" + buildable + "type=" + type + "ROFMod=" + ROFMod + "damageMod=" + damageMod + "projectileSpeedMod=" + projectileSpeedMod + "splashMod=" + splashMod + "buildTimeMod=" + buildTimeMod + '}';
    }
}
